
#[derive(Debug)]
#[derive(Default)]
#[derive(PartialEq)]
#[derive(PartialOrd)]
#[derive(Copy, Clone)]
#[derive(::serde::Serialize, ::serde::Deserialize)]
pub struct Vector2
{
    pub x: f64,
    pub y: f64
}
impl ::std::ops::Add for Vector2
{
    type Output = Self;

    fn add(self, rhs: Self) -> Self::Output {
        Self {
            x: self.x + rhs.x,
            y: self.y + rhs.y
        }
    }
}
impl ::std::ops::AddAssign for Vector2
{
    fn add_assign(&mut self, rhs: Self) {
        self.x = self.x + rhs.x;
        self.y = self.y + rhs.y;
    }
}
impl ::std::ops::Sub for Vector2
{
    type Output = Self;

    fn sub(self, rhs: Self) -> Self::Output {
        Self {
            x: self.x - rhs.x,
            y: self.y - rhs.y
        }
    }
}
impl ::std::ops::Mul for Vector2
{
    type Output = Self;

    fn mul(self, rhs: Self) -> Self::Output {
        Self {
            x: self.x * rhs.x,
            y: self.y * rhs.y
        }
    }
}
impl ::std::ops::Div for Vector2
{
    type Output = Self;

    fn div(self, rhs: Self) -> Self::Output {
        Self {
            x: self.x / rhs.x,
            y: self.y / rhs.y
        }
    }
}
impl ::std::ops::Neg for Vector2
{
    type Output = Self;

    fn neg(self) -> Self::Output {
        Self {
            x: -self.x,
            y: -self.y
        }
    }
}
pub type Point = Vector2;
impl Point
{
    pub fn length(&self) -> f64 {
        // |向量self|
        (self.x * self.x + self.y * self.y).sqrt()
    }

    pub fn distance(&self, other: &Self) -> f64
    {
        // 向量self - 向量other = 向量self-other;
        // 再求 |向量self-other|
        let x = self.x - other.x;
        let y = self.y - other.y;
        (x * x + y * y).sqrt()
    }

    /// 当 x = 0 时 斜率不存在
    pub fn tan(&self) -> f64
    {
        // k = (y2 - y1) / (x2 - x1)
        (self.y - 0.0) / (self.x - 0.0)
    }
}



#[derive(Debug)]
#[derive(Default)]
#[derive(PartialEq)]
#[derive(Copy, Clone)]
pub struct Segment
{
    pub(crate) point1: Point,
    pub(crate) point2: Point
}
impl Segment
{
    pub fn new(point1: Point, point2: Point) -> Self
    {
        if point1 == point2 {
            panic!("it is not a segment");
        }

        Self {
            point1,
            point2
        }
    }

    pub fn point1(&self) -> &Point { &self.point1 }
    pub fn point2(&self) -> &Point { &self.point2 }
    pub fn get_p1(&self) -> &Point { &self.point1 }
    pub fn get_p2(&self) -> &Point { &self.point2 }

    pub fn sin(&self) -> f64
    {
        let length = self.length();
        (self.point2.y - self.point1.y) / length
    }


    pub fn cos(&self) -> f64
    {
        let length = self.length();
        (self.point2.x - self.point1.x) / length
    }


    pub fn tan(&self) -> f64
    {
        // k = (y2 - y1) / (x2 - x1)
        (self.point2.y - self.point1.y) / (self.point2.x - self.point1.x)
    }


    pub fn length(&self) -> f64
    {
        let p2p1 = self.point2 - self.point1;
        (p2p1.x * p2p1.x + p2p1.y * p2p1.y).sqrt()
    }

    pub fn distance(&self, other: &Self) -> f64
    {
        let tan_value = self.tan();
        if tan_value != other.tan() {
            panic!("暂不支持求两条不平行线段的距离");
        }


        // y = kx + b
        // b = y / kx
        let b1: f64 = self.point1.y / tan_value * self.point1.x;    //segment1 self
        let b2: f64 = other.point1.y / tan_value * other.point1.x;  //segment2 other


        // y = k * x + b
        // x = (y - b) / k
        // y = kx + b -> kx - y + b = 0
        // kx - y + b = 0
        // 一般式 ax + by + c = 0
        // 距离公式 d = |c1 - c2| / (a * a + b * b)^1/2
        // k -> a, -1 -> b, b -> c
        // a^2 = k * k
        // b^2 = 1
        let d: f64 = (b1 - b2).abs() / (tan_value * tan_value + 1.0).sqrt();
        d
    }


    fn x_near_00_point(&self) -> &Point
    {
        let mut x1 = self.point1.x;
        let mut x2 = self.point2.x;

        if x1 < 0.0 { x1 = -x1; }
        if x2 < 0.0 { x2 = -x2; }

        if x1 == x2 {
            return self.y_near_00_point();
        }

        /* x1 > x2, x2 near 0 */
        if x1 > x2 {
            &self.point2
        } else {// x1 < x2
            &self.point1
        }
    }

    fn y_near_00_point(&self) -> &Point
    {
        let mut y1 = self.point1.y;
        let mut y2 = self.point2.y;

        if y1 < 0.0 { y1 = -y1; }
        if y2 < 0.0 { y2 = -y2; }

        if y1 == y2 {
            return self.x_near_00_point();
        }

        /* y1 > y2, y2 near 0 */
        if y1 > y2 {
            &self.point2
        } else {// y1 < y2
            &self.point1
        }
    }


    pub fn near_00_point(&self) -> &Point
    {
        let get_length = |x: f64, y: f64|{
            (x * x + y * y).sqrt()
        };

        let length1 = get_length(self.point1.x, self.point1.y);
        let length2 = get_length(self.point2.x, self.point2.y);

        if length1 == length2 {
            eprintln!("the distance of segment's points are same");
            return &self.point1;
        }

        /* length1 > length2, point1 farther */
        if length1 > length2 {
            &self.point2
        } else {
            &self.point1
        }
    }



    /**
     * 判断两条线段是否相交
     */
    pub fn cross(&self, other: &Self) -> bool
    {
        /*
        let 向量1: Point = Point {
            x: self.point2.x - self.point1.x,
            y: self.point2.y - self.point1.y
        };
        let 向量2: Point = Point {
            x: other.point2.x - other.point1.x,
            y: other.point2.y - other.point1.y
        };
        // 向量a * 向量b = |向量a| * |向量b| * cos<向量a, 向量b>
        // 夹角为 0（平行），则数量积为 0
        let 数量积 = 向量1.x * 向量2.x + 向量1.y + 向量2.y;

        /* 平行 */
        if 数量积 == 0.0 {
            todo!();
        }
        */


        // k = (y2 - y1) / (x2 - x1)
        let k_self= self.tan();
        let k_other = other.tan();

        /* 平行 */
        // 平行不相交 
        if k_self == k_other {
            return false;
        }
        

        // y = kx + b
        // b = y - kx
        let b_self = self.point1.y - k_self * self.point1.x;
        let b_other = other.point1.y - k_other * other.point1.x;

        // y = kx + b
        // x = (y - b) / k
        // k_self * x + b_self = k_other * x + b_other
        // k_self * x + (b_self - b_other) = k_other * x
        // k_self * x + b_difference = k_other * x
        // k_self * x - k_other * x + b_difference
        // (k_self - k_other) x = b_difference
        // x = b_difference / (k_self - k_other)
        let b_difference = b_self - b_other;
        let 交点x = b_difference / (k_self - k_other);
        let 交点y = k_self * 交点x + b_self;
        let 交点 = Point {
            x: 交点x,
            y: 交点y
        };

        // 判断交点与 两条线段两点的距离 是否 在两条线段的长度范围内
        let length_self = self.length();
        let length_other = other.length();
        if  self.point1.distance(&交点) < length_self
            && self.point2.distance(&交点) < length_self
            && other.point1.distance(&交点) < length_other
            && other.point2.distance(&交点) < length_other
        {
            return true;
        }

        false
    }

}


#[derive(Debug)]
#[derive(Default)]
#[derive(PartialEq)]
#[derive(Copy, Clone)]
#[derive(::serde::Serialize, ::serde::Deserialize)]
pub struct Rectangle
{
    pub left: f64,  // x
    pub top: f64,   // y
    pub right: f64, // x + width
    pub bottom: f64 // y + height
}
impl Rectangle
{
    pub fn cross(&self, other: &Rectangle) -> bool
    {
        /* 区间 r2left <= r1left <= r2right */
        /* 区间 r2left <= r1right <= r2right */
        let r2left = &other.left;
        let r2right = &other.right;
        let r1left = &self.left;
        let r1right = &self.right;

        /* 区间 r2top <= r1top <= r2bottom */
        /* 区间 r2top <= r1bottom <= r2bottom */
        let r2top = &other.top;
        let r2bottom = &other.bottom;
        let r1top = &self.top;
        let r1bottom = &self.bottom;


        if  (
                (r2left <= r1left && r1left <= r2right)
                ||
                (r2left <= r1right && r1right <= r2right)
            )
            &&
            (
                (r2top <= r1top && r1top <= r2bottom)
                ||
                (r2top <= r1bottom && r1bottom <= r2bottom)
            )
        {
            return true;
        }
        false
    }
}


#[derive(Debug)]
#[derive(Default)]
#[derive(PartialEq)]
#[derive(Copy, Clone)]
pub struct Circle
{
    pub center: Point,  // 圆心坐标
    pub radius: f64
}
impl Circle
{
    pub fn cross(&self, other: &Circle) -> bool
    {
        todo!()
    }
}


pub fn segment_cross(s1: &Segment, s2: &Segment) -> bool
{
    s1.cross(s2)
}


pub fn rectangle_cross(r1: &Rectangle, r2: &Rectangle) -> bool
{
    r1.cross(r2)
}


pub fn circle_cross(c1: &Circle, c2: &Circle) -> bool
{
    c1.cross(c2)
}


